package net.vinote.smart.platform.service.dw;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;

import javax.servlet.http.HttpServletRequest;

import net.vinote.smart.platform.comm.DateFunction;
import net.vinote.smart.platform.comm.PlatformConst;
import net.vinote.smart.platform.comm.StringFunction;
import net.vinote.smart.platform.exception.PlatformException;
import net.vinote.smart.platform.module.database.DBManager;
import net.vinote.smart.platform.module.database.DBManagerFactory;
import net.vinote.smart.platform.module.database.bo.BizObject;
import net.vinote.smart.platform.module.database.bo.DBQuery;
import net.vinote.smart.platform.module.log.RunLogger;
import net.vinote.smart.platform.service.DWException;
import net.vinote.smart.platform.service.SRE;
import net.vinote.smart.platform.service.bean.DataWindowCatalog;
import net.vinote.smart.platform.service.bean.DataWindowLibrary;
import net.vinote.smart.platform.service.bean.User;
import net.vinote.smart.platform.service.dw.component.ButtonComp;
import net.vinote.smart.platform.service.dw.component.Component;
import net.vinote.smart.platform.service.dw.handler.CommonHandler;
import net.vinote.smart.platform.service.dw.handler.HandlerPerimissionAnnotation;
import net.vinote.smart.platform.service.dw.handler.VirtualCommonHandler;
import net.vinote.smart.platform.service.dw.html.ButtonTag;
import net.vinote.smart.platform.service.dw.html.HtmlTag;
import net.vinote.smart.platform.service.dw.html.UIEvent;
import net.vinote.smart.platform.service.dw.html.css.CSS;
import net.vinote.smart.platform.service.util.Permission;
import net.vinote.smart.platform.service.util.Permission.PermissionUtil;

public abstract class DataWindow implements ButtonComp {
	private static final RunLogger logger = RunLogger.getLogger();

	public static final String DEFUALT_FORM_ID = "dwForm";// 默认的表单ID

	public static final String DEFUALT_FORM_NAME = "dwForm";// 默认的表单Name

	private String appendSql = "";

	private ButtonTag[] btnComp; // 按钮组件

	private HttpServletRequest request;// Http Request

	// 添加的额外组件
	private int btnPosition = 0; // 按钮组件的放置位置

	private DataWindowCatalog dwCatalog;// dataWindow_catalog业务对象

	private List<BizObject> dataList;// 查询数据结果集

	private CommonHandler handler;// 显示模板的handler类

	private Map<String, HtmlTag> htmlTagMap;// 加载列表中要展示的字段

	private Set<String> disabledFieldSet = new HashSet<String>();// 存放需要失效的字段

	// private Map<String, Boolean> readOnlyMap = new HashMap<String,
	// Boolean>();// 更新字段是否只读
	private Map<String, Map<CSS, String>> fieldsCssAttributesMap = new HashMap<String, Map<CSS, String>>();

	// 存储当前显示模板定义的所有事件
	private Map<String, Map<String, String>> fieldEventsMap = new HashMap<String, Map<String, String>>();

	private boolean formDisabld = false;// 是否禁用表单

	private boolean isReadOnly = false;

	private String formID;

	private String formName;

	private String doNo;

	private int showStyle;

	private boolean isInsert = false;

	/** 是否为虚拟模板,即显示模板中任一字段都不映射于表字段 */
	protected boolean isVirtual = false;

	/** 虚拟模板标识 */
	public static final String VIRTUAL_FLAG = "V";

	private String whereSql;

	private String[] paramVal;

	private int total;// 数据总量

	public DataWindow(HttpServletRequest request) {
		this.request = request;
	}

	public DataWindow() {
	}

	public String getHtml() throws SQLException {
		initialize();
		StringBuffer sb = new StringBuffer();
		if (!formDisabld && !isReadOnly) {
			sb.append("<form id='").append(getFormID()).append("' name='")
					.append(getFormName()).append("'>");
		}

		if (!isReadOnly && (btnPosition & Component.NORTH) > 0) {
			sb.append(getButtonHtml());
		}
		sb.append("<input type='hidden' name='doNo' value='").append(doNo)
				.append("'/>");
		sb.append(getDWHtml());// 加载显示模板html代码
		if (!isReadOnly && (btnPosition & Component.SORTH) > 0) {
			if (this instanceof DataWindowInfo) {
				sb.append("<div style='text-align:center;'>" + getButtonHtml()
						+ "</div>");
			} else {
				sb.append(getButtonHtml());
			}
		}
		if (!formDisabld && !isReadOnly) {
			sb.append("</form>");
		}
		// 添加jquery语法的字段事件
		sb.append("<script>");
		sb.append("$(function(){");
		for (Entry<String, Map<String, String>> entry : fieldEventsMap
				.entrySet()) {
			String tagName = entry.getKey();
			Map<String, String> eventMap = entry.getValue();
			sb.append("$('*[name=\"").append(tagName).append("\"]')");
			for (Entry<String, String> eEntry : eventMap.entrySet()) {
				String name = eEntry.getKey();
				String event = eEntry.getValue();
				sb.append('.');
				if (name.startsWith("on")) {
					sb.append(name.substring(2));
				} else {
					sb.append(name);
				}
				sb.append("(function(){");
				sb.append(event);
				sb.append(";})");
			}
			sb.append(";");
		}
		sb.append("});");
		sb.append("</script>");
		return sb.toString();
	}

	/**
	 * 初始化显示模板
	 * 
	 * @param doNo
	 * @throws SQLException
	 */
	protected void initialize() throws SQLException {
		initBasisData();// 初始化dono对应的DataObject_Catalog数据对象
		initHtmlTags();// 初始化所要在页面展示的Html标签集合
		// 虚表模板无需初始化数据
		if (isVirtual) {
			initVirtualBizObjectData();// 初始化数据
		} else {
			initBizObjectData();// 初始化数据
		}
		// initVirtaulData()
	}

	private void initVirtualBizObjectData() {
		VirtualCommonHandler handler = (VirtualCommonHandler) this.handler;
		dataList = handler.initDataList();
		if (showStyle == PlatformConst.LIST) {
			// 统计数据量
			total = handler.initDataCount();
		}
		if (dataList == null || dataList.size() == 0) {
			isInsert = true;
		}

	}

	/**
	 * 初始化基础数据
	 * 
	 * @throws SQLException
	 */
	private void initBasisData() throws SQLException {
		dwCatalog = SRE.getDataWindowCatalog(doNo);
		if (dwCatalog == null) {
			throw new DWException("现实模板不存在:doNo=" + doNo);
		}
		isVirtual = VIRTUAL_FLAG.equalsIgnoreCase(dwCatalog.getMainTable());
		/** 初始化handler */
		handler = initHandlerClass(dwCatalog.getHandler(), isVirtual);
		handler.setRequest(request);
		// 是否启用了防火墙进行 权限校验
		if (SRE.getSystemParameter().getFirewall() == PlatformConst.Yes) {
			HandlerPerimissionAnnotation annotation = handler.getClass()
					.getAnnotation(HandlerPerimissionAnnotation.class);
			if (annotation == null) {
				throw new PlatformException(dwCatalog.getHandler()
						+ "未指定权限,操作存在隐患!");
			}
			Permission permission = isVirtual ? annotation.virtual()
					: annotation.query();
			if (permission == null
					|| ((permission.value() == null || permission.value().length == 0) && (permission
							.ExtendedPermision() == null || permission
							.ExtendedPermision().length == 0))) {
				throw new PlatformException(dwCatalog.getHandler()
						+ "未指定权限,操作存在隐患!");
			}
			if (!PermissionUtil.hasPermission(permission, request)) {
				throw new PlatformException(dwCatalog.getHandler() + "权限校验失败"
						+ permission);
			}
		}

		if (request != null) {
			isReadOnly = "true".equals(request.getAttribute("ReadOnly"))
					|| "true".equals(request.getParameter("ReadOnly"));
		}
	}

	/**
	 * 装载显示模板的HTML标签集合
	 * 
	 * @return
	 * @throws SQLException
	 */
	private void initHtmlTags() throws SQLException {
		if (htmlTagMap != null) {
			htmlTagMap.clear();
			htmlTagMap = null;
		}
		List<DataWindowLibrary> list = SRE.getDataWindowLibrary(doNo);
		htmlTagMap = new LinkedHashMap<String, HtmlTag>();
		for (DataWindowLibrary bo : list) {
			String dataObj = StringFunction.nullToBlank(bo.getDataObj()).trim();
			HtmlTag tag = new HtmlTag(showStyle);
			String filedCode = bo.getFieldCode().toUpperCase();
			tag.setId(filedCode);
			// if (dataObj.length() > 0 && dataObj.indexOf(".") == -1) {
			// tag.setName(dataObj.toUpperCase() + "."
			// + bo.getFieldCode().toUpperCase());
			// } else {
			// tag.setName(bo.getFieldCode().toUpperCase());
			// }
			tag.setName(filedCode);
			tag.setTagName(bo.getFieldName());// 字段中文名
			tag.setIsReadOnly(isReadOnly || bo.isReadOnly());// 是否只读
			tag.setVisible(bo.isVisible());// 是否可见
			tag.setIsFilter(bo.isFilter());// 是否可查询
			tag.setIsRequired(bo.isRequired());
			tag.setAfterField(bo.getAfterField());// 后缀
			tag.setShowTag(bo.getShowTag());// 显示的HTML标签
			tag.setColField(bo.getColField().toUpperCase());
			tag.setHtmlSource(bo.getHtmlSource());
			tag.setHtmlVal(bo.getHtmlVal());
			tag.addStyle(bo.getHtmlStyle());
			tag.setDataObj(dataObj);
			tag.setColSpan(bo.getColspan());
			tag.setRowSpan(bo.getRowspan());
			// 添加字段事件
			Map<String, String> eventMap = SRE.getDataObjectEvent(doNo,
					bo.getFieldCode());
			if (eventMap != null && eventMap.size() > 0) {
				fieldEventsMap.put(tag.getName(), eventMap);
				// tag.addAttributes(eventMap);
			}

			htmlTagMap.put(filedCode, tag.getTagInstance());
		}
	}

	/**
	 * 加载显示模板定义字段的数据集
	 * 
	 * @param colFields
	 *            要查询的字段名
	 * @param bo
	 *            DataObject_Catalog对像，定义了查询条件参数
	 */
	private void initBizObjectData() throws SQLException {
		Collection<HtmlTag> tagColl = htmlTagMap.values();
		List<String> fieldList = new ArrayList<String>(tagColl.size());
		List<String> virtaulFieldList = new ArrayList<String>();// 存储虚字段
		for (HtmlTag tag : tagColl) {
			String dataObj = StringFunction.nullToBlank(tag.getDataObj())
					.trim();
			if (dataObj.equals("")) {
				virtaulFieldList.add(tag.getName());
			} else {
				fieldList.add(dataObj + "." + tag.getColField());
				// fieldList.add(tag.getColField());
			}
		}
		String[] fieldArray = new String[fieldList.size()];
		fieldList.toArray(fieldArray);
		String unionTable = dwCatalog.getUnionTable();
		if (unionTable != null && "".equals(unionTable.trim()))
			unionTable = null;
		if (whereSql == null)
			whereSql = dwCatalog.getWhereSQL() + " " + appendSql;
		DBManager bm = DBManagerFactory.getInstance(dwCatalog.getMainTable());
		DBQuery dataDuery = bm.createQuery(fieldArray, whereSql, paramVal,
				unionTable);
		wrapQuery(dataDuery);
		dataList = dataDuery.getResultList();// 分页查询数据
		if (showStyle == PlatformConst.LIST) {
			// 统计数据量
			DBQuery query = bm.createQuery(fieldArray, whereSql, paramVal,
					unionTable);
			query.setQuerySql("select count(1) totalNum from ("
					+ query.getQuerySql() + ") as countNumSQL");
			total = Integer.parseInt(query.getSingleResult("totalNum")
					.getAttribute("totalNum"));
		}
		if (dataList == null || dataList.size() == 0) {
			isInsert = true;
		}
	}

	protected void wrapQuery(DBQuery query) {

	}

	/**
	 * 更新显示要素
	 */
	private Map<String, HtmlTag> updateHtmlTagsByHandler(BizObject bo) {
		Map<String, HtmlTag> htmlTagMapBak = new LinkedHashMap<String, HtmlTag>();
		htmlTagMapBak.putAll(htmlTagMap);
		// 加载handler类中的初始化控制

		if (bo == null) {
			bo = new BizObject();
		}
		if (isVirtual) {
			((VirtualCommonHandler) handler).initDisplayForVirtual(bo);
		} else if (isInsert) {
			// 初始化基础数据
			User curUser = (User) (request.getSession().getAttribute("user"));
			if (curUser != null) {
				bo.setAttribute("INPUTUSERID", curUser.getUserID());
			}
			bo.setAttribute("INPUTDATE", DateFunction.getCurrentTime());
			handler.initDisplayForAdd(bo);
		} else {
			handler.initDisplayForEdit(bo);
		}
		// 将显示字段赋予默认值
		Map<String, String> defaultVal = handler.getDefaultValue();
		for (String key : defaultVal.keySet()) {
			bo.setAttribute(key, defaultVal.get(key));
		}
		// 设置自段的属性
		Map<String, Map<CSS, String>> handlerFieldsCSS = handler
				.getFieldsCssAttributes();
		handlerFieldsCSS.putAll(fieldsCssAttributesMap);// 加载显示模板中对字段的只读属性配置
		for (String field : handlerFieldsCSS.keySet()) {
			HtmlTag tag = htmlTagMapBak.get(field);
			if (tag != null) {
				Map<CSS, String> cssMap = handlerFieldsCSS.get(field);
				for (CSS css : cssMap.keySet()) {
					tag.setAttribute(css.getCSS(), cssMap.get(css));
				}
			} else {
				logger.log(Level.FINE, "could not find filed:" + field);
			}
		}

		// 重置HtmlTag属性值
		Map<String, Map<String, Object>> htmlTagFieldMap = handler
				.getHtmlTagFieldMap();
		for (String field : htmlTagFieldMap.keySet()) {
			HtmlTag tag = htmlTagMapBak.get(field);
			if (tag != null) {
				Map<String, Object> attrMap = htmlTagFieldMap.get(field);
				Class<?> clazz = tag.getClass();
				while (!clazz.getName().equals(HtmlTag.class.getName())) {
					clazz = clazz.getSuperclass();
				}
				for (String attr : attrMap.keySet()) {
					try {
						Field f = clazz.getDeclaredField(attr);
						if (f != null) {
							f.setAccessible(true);
							f.set(tag, attrMap.get(attr));
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			} else {
				logger.log(Level.FINE, "could not find filed:" + field);
			}
		}

		for (String f : disabledFieldSet) {
			htmlTagMapBak.remove(f);
		}
		return htmlTagMapBak;
	}

	/**
	 * 实例化一个Handler类用于处理模板中的数据
	 * 
	 * @param handlerName
	 * @param isVirtual2
	 * @return
	 */
	private CommonHandler initHandlerClass(String handlerName, boolean virtual) {
		CommonHandler handlerClass = null;
		if (handlerName == null || "".equals(handlerName.trim())) {
			return isVirtual ? new VirtualCommonHandler() : new CommonHandler();
		}
		try {
			Object obj = Class.forName(handlerName).newInstance();
			if (virtual && (obj instanceof VirtualCommonHandler)) {
				handlerClass = (VirtualCommonHandler) obj;
			} else if (!virtual && (obj instanceof CommonHandler)) {
				handlerClass = (CommonHandler) obj;
			}
		} catch (Exception e) {
			logger.log(Level.SEVERE, e.getMessage(), e);
		}
		if (handlerClass == null) {
			throw new DWException("无效Handler类:" + handlerName);
		}
		return handlerClass;
	}

	public void addButtons(String[][] buttons, int position) {
		btnPosition = position;
		if (buttons != null) {
			int btnNum = buttons.length;
			btnComp = new ButtonTag[btnNum];
			for (int i = 0; i < btnNum; i++) {
				btnComp[i] = new ButtonTag();
				btnComp[i].setValue(buttons[i][0]);
				btnComp[i].addEvent(UIEvent.ON_CLICK, buttons[i][1]);
			}
		}
	}

	public void addButtons(ButtonTag[] buttons, int position) {
		btnPosition = position;
		if (buttons != null) {
			btnComp = buttons;
		}
	}

	// 以下提供对添加组件的支持
	public String getButtonHtml() {
		StringBuffer sb = new StringBuffer();
		if (btnComp != null) {
			for (ButtonTag btn : btnComp) {
				sb.append(btn.getHtml());
			}
		}
		return sb.toString();
	}

	public ButtonTag[] getBtnComp() {
		return btnComp;
	}

	public List<BizObject> getDataList() {
		return dataList;
	}

	protected abstract String getDWHtml() throws SQLException;

	public String getFormID() {
		return StringFunction.getValue(formID, DEFUALT_FORM_ID);
	}

	public String getFormName() {
		return StringFunction.getValue(formName, DEFUALT_FORM_NAME);
	}

	public Map<String, HtmlTag> getHtmlTagMap(BizObject bo) {
		Map<String, HtmlTag> tagMap = updateHtmlTagsByHandler(bo);
		// 更新虚字段
		try {
			for (String key : tagMap.keySet()) {
				HtmlTag tag = tagMap.get(key);
				if (StringFunction.nullToBlank(tag.getDataObj()).equals("")) {
					if (PlatformConst.HtmlSource.JAVA.equals(tag
							.getHtmlSource())) {
						// 格式:com.zjw.Test.test(param);
						String htmlVal = tag.getHtmlVal();
						int index = htmlVal.lastIndexOf(".");
						int lparamIndex = htmlVal.indexOf("(");// 左括号
						int rparamIndex = htmlVal.indexOf(")");
						String className = htmlVal.substring(0, index);
						String method = htmlVal.substring(index + 1,
								lparamIndex);
						String[] param = htmlVal.substring(lparamIndex + 1,
								rparamIndex).split(",");
						String[] value = new String[param.length];
						Class<?>[] paramClass = new Class[param.length];
						for (int i = 0; i < param.length; i++) {
							paramClass[i] = String.class;
							if (bo != null) {
								value[i] = bo.getAttribute(param[i]);
							} else {
								value[i] = "";
							}
						}
						// 缓存java对象以提高性能
						DataWindowClass dwClass = SRE.getAttribute(
								DataWindowClassModify.class.getName() + "."
										+ PlatformConst.SRE_PREFIX_CLASS_OBJECT
										+ className + "@" + method + "@"
										+ param.length, DataWindowClass.class);
						if (dwClass == null) {
							DataWindowClassModify modify = new DataWindowClassModify();
							dwClass = new DataWindowClass();
							Class<?> clazz = Class.forName(className);
							Method m = clazz.getMethod(method, paramClass);
							dwClass.setMethod(m);
							dwClass.setObject(clazz.newInstance());
							modify.put(PlatformConst.SRE_PREFIX_CLASS_OBJECT
									+ className + "@" + method + "@"
									+ param.length, dwClass);
							SRE.addAttribute(modify);
						}
						// Class clazz = Class.forName(className);
						// Object obj = clazz.newInstance();
						/*
						 * String val = clazz.getMethod(method, paramClass)
						 * .invoke(obj, value).toString();
						 */
						String val = dwClass.getMethod()
								.invoke(dwClass.getObject(), value).toString();
						tag.setValue(val);
						if (bo != null) {
							bo.setAttribute(tag.getName(), val);
						}

					} else {
						if (bo != null) {
							tag.setValue(bo.getAttribute(tag.getName()));
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return tagMap;
	}

	public String getDoNo() {
		return doNo;
	}

	public void setDoNo(String doNo) {
		this.doNo = doNo;
	}

	public void setAppendSql(String appendSql) {
		this.appendSql = appendSql;
	}

	/**
	 * 指定失效的字段,以逗号分隔各字段<br/>
	 * 例:"field1,field2"
	 * 
	 * @param fields
	 */
	public void setDisabled(String fields) {
		if (fields != null) {
			String[] fieldArray = fields.split(",");
			for (String field : fieldArray) {
				disabledFieldSet.add(field);
			}
		}
	}

	/***
	 * 设置字段是否只读
	 */
	public void setReadOnly(String fields, boolean flag) {
		if (fields != null) {
			fields = fields.toUpperCase();
			String[] fieldArray = fields.split(",");
			for (String field : fieldArray) {
				Map<CSS, String> fieldCssMap = fieldsCssAttributesMap
						.get(field);
				if (isReadOnly) {// 设置字段的只读属性
					if (fieldCssMap == null) {
						fieldCssMap = new HashMap<CSS, String>();
						fieldsCssAttributesMap.put(field, fieldCssMap);
					}
					fieldCssMap.put(CSS.READONLY, CSS.CSS_READONLY);
				} else {
					if (fieldCssMap != null) {
						fieldCssMap.remove(CSS.READONLY);// 移除字段的只读属性
					}
				}
			}
		}
	}

	public void setWhereSql(String whereSql) {
		this.whereSql = whereSql;
	}

	public void setShowStyle(int showStyle) {
		this.showStyle = showStyle;
	}

	public boolean isInsert() {
		return isInsert;
	}

	protected void setInsert(boolean isInsert) {
		this.isInsert = isInsert;
	}

	public void setParamVal(String... paramVal) {
		this.paramVal = paramVal;
	}

	public String[] getParamVal() {
		return paramVal;
	}

	public String getWhereSql() {
		return whereSql;
	}

	protected void setHttpRequest(HttpServletRequest request) {
		this.request = request;
	}

	public boolean isFormDisabld() {
		return formDisabld;
	}

	public void setFormDisabld(boolean formDisabld) {
		this.formDisabld = formDisabld;
	}

	public boolean isReadOnly() {
		return isReadOnly;
	}

	public void setReadOnly(boolean isReadOnly) {
		this.isReadOnly = isReadOnly;
	}

	public int getTotal() {
		return total;
	}

	public DataWindowCatalog getDwCatalog() {
		return dwCatalog;
	}

}
